package com.example.coordinartordemo.demo6;

import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Scroller;
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.example.coordinartordemo.R;

import java.lang.ref.WeakReference;

public class HeaderScrollingBehavior extends CoordinatorLayout.Behavior<RecyclerView> {

    private boolean isExpanded = false;
    private boolean isScrolling = false;

    private WeakReference<View> dependentView;

    /** 用来实现用户释放手指后的滑动动画 */
    private Scroller scroller;

    /** 用来驱动Scroller运行 */
    private Handler handler;

    private Runnable flingRunable = new Runnable() {
        @Override
        public void run() {
            if (scroller.computeScrollOffset()){
                getDependentView().setTranslationY(scroller.getCurrY());
                handler.post(this);
            }else {
                isExpanded = getDependentView().getTranslationY() != 0;
                isScrolling = false;
            }
        }
    };

    public HeaderScrollingBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        scroller = new Scroller(context);
        handler = new Handler();
    }

    /**
     * 此Behavior是否依赖于某个view
     * @param parent
     * @param child
     * @param dependency
     * @return
     */
    @Override
    public boolean layoutDependsOn(@NonNull CoordinatorLayout parent, @NonNull RecyclerView child, @NonNull View dependency) {
       if (null != dependency && dependency.getId() == R.id.scrolling_header){
           dependentView = new WeakReference<>(dependency);
           return true;
       }
       return false;
    }

    /**
     * 负责对被此Behavior控制的视图进行布局
     * @param parent
     * @param child
     * @param layoutDirection
     * @return
     *
     * 此处处理：将目标视图的高度减去HeaderView折叠后的高度
     */
    @Override
    public boolean onLayoutChild(@NonNull CoordinatorLayout parent, @NonNull RecyclerView child, int layoutDirection) {
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
        if (lp.height == CoordinatorLayout.LayoutParams.MATCH_PARENT){
            child.layout(0,0,parent.getWidth(), (int) (parent.getHeight() - getDependentViewCollapsedHeight()));
            return true;
        }

        return super.onLayoutChild(parent, child, layoutDirection);
    }

    /**
     * 当依赖视图发生变化时，会被调用。
     * @param parent
     * @param child
     * @param dependency
     * @return
     * 此处处理：通过当前依赖视图的位移，计算出一个位移因数（0~1），对应到依赖视图的缩放和透明度
     */
    @Override
    public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent, @NonNull RecyclerView child, @NonNull View dependency) {
        Resources resources = getDependentView().getResources();
        final float progress = 1.f - Math.abs(dependency.getTranslationY() / (dependency.getHeight() - resources.getDimension(R.dimen.collapsed_header_height)));
        child.setTranslationY(dependency.getHeight() + dependency.getTranslationY());

        float scale = 1 + 0.4f * (1.f - progress);
        dependency.setScaleX(scale);
        dependency.setScaleY(scale);

        dependency.setAlpha(progress);
        return true;
    }

    /**
     * 用户按下手指时触发，询问nestedScrollParent是否处理这次滑动。如果返回false,后面一些列的回调函数都不会被调用
     * @param coordinatorLayout
     * @param child
     * @param directTargetChild
     * @param target
     * @param axes 滑动方向。ViewCompat.SCROLL_AXIS_HORIZONTAL   ViewCompat.SCROLL_AXIS_VERTICAL
     * @param type 滑动的类型
     * @return true:表示我要处理这次滑动，false:不处理这次滑动，你想咋滑就咋滑
     *
     * 此处处理：只处理竖直方向的滑动
     */
    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull RecyclerView child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }

    /**
     * nestedScrollParent接触处理本次滑动时，被调用。做一些准备工作，比如让之前的滑动动画结束
     * @param coordinatorLayout
     * @param child
     * @param directTargetChild
     * @param target
     * @param axes
     * @param type
     */
    @Override
    public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout, @NonNull RecyclerView child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {

        scroller.abortAnimation();
        isScrolling = false;

        super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, axes, type);
    }

    /**
     * nestedScrollChild即将被滑动时调用，可以在这里做一些处理。
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dx 用户水平方向的滚动距离
     * @param dy 用户竖直方向的滚动距离
     * @param consumed 修改这个数组来表示你到底处理掉了多少像素。假设用户滑动了 100px，你做了 90px 的位移，那么就需要把 consumed[1] 改成 90（下标 0、1 分别对应 x、y 轴），这样 NSC 就能知道，然后继续处理剩下的 10px
     * @param type
     */
    @Override
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull RecyclerView child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {
        if (dy < 0) return;

        View dependentView = getDependentView();
        float newTranslateY = dependentView.getTranslationY() - dy;
        float minHeaderTranslate = - (dependentView.getHeight() - getDependentViewCollapsedHeight());
        if (newTranslateY > minHeaderTranslate){
            dependentView.setTranslationY(newTranslateY);
            consumed[1] = dy;
        }
    }

    /**
     * 进行嵌套滑动时被调用
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param dxConsumed target已经消费的x方向的距离
     * @param dyConsumed target已经消费的y方向的距离
     * @param dxUnconsumed x方向剩下的滚动距离
     * @param dyUnconsumed y方向剩下的滚动距离
     * @param type
     */
    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull RecyclerView child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        if (dyUnconsumed > 0) return;

        View dependentView = getDependentView();
        float newTranslateY = dependentView.getTranslationY() - dyUnconsumed;
        final float maxHeaderTranslate = 0 ;
        if (newTranslateY < maxHeaderTranslate){
            dependentView.setTranslationY(newTranslateY);
        }
    }


    /**
     * 用户松开手指并且发生惯性滑动动作之前调用。
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param velocityX x方向的速度
     * @param velocityY y方向的速度
     * @return
     */
    @Override
    public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull RecyclerView child, @NonNull View target, float velocityX, float velocityY) {
        return onUserStopDragging(velocityY);
    }

    /**
     *  嵌套滚动结束，可以用来清除滚动状态等
     * @param coordinatorLayout
     * @param child
     * @param target
     * @param type
     */
    @Override
    public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull RecyclerView child, @NonNull View target, int type) {
        if (!isScrolling) onUserStopDragging(800);
    }

    private float getDependentViewCollapsedHeight() {
        return getDependentView().getResources().getDimension(R.dimen.collapsed_header_height);
    }

    private View getDependentView(){
        return dependentView.get();
    }

    private boolean onUserStopDragging(float velocity){
        View dependentView = getDependentView();
        float translateY = dependentView.getTranslationY();
        float minHeaderTranslate = -(dependentView.getHeight() - getDependentViewCollapsedHeight());
        if (translateY == 0 || translateY == minHeaderTranslate) return false;

        boolean targetState;
        if (Math.abs(velocity) <= 800){
            if (Math.abs(translateY) < Math.abs(translateY - minHeaderTranslate)){
                targetState = false;
            }else {
                targetState = true;
            }
        }else {
            if (velocity > 0){
                targetState = true;
            }else {
                targetState = false;
            }
        }

        float targetTranslateY = targetState ? minHeaderTranslate : 0;
        scroller.startScroll(0,(int)translateY,0,(int)(targetTranslateY - translateY));
        handler.post(flingRunable);
        isScrolling = true;

        return true;
    }
}
